<?php
/**
* File:        Uploader.class.php
* License:     GNU
*
* @link http://www.fanbin.name/
* @copyright 2007 Fanbin
* @author Fanbin <fanbincn@gmail.com>
* @version 1.0
*/
class Uploader
{
    private $name;                //文件被上传之前的名称
    private $size;                //文件大小
    private $tmp_name;            //文件在临时目录中的名字
    private $type;                //文件的MIME类型，在此类中未使用
    private $error;               //上传错误信息编号
    private $fileExt;             //文件的扩展名
    private $validExt = array();  //允许的扩展名
    private $newName;             //文件上传后的名称
    private $maxSize;             //允许的最大大小
    private $upDir;               //上传到的目录
    private $allowOverride;       //是否允许覆盖，默认不允许 
    private $timeStamp;           //时间戳，用于定义目录名和时间名
    
    
    /**
     * 构造器
     *
     * @param string $fileInput 上传表单中file域的name属性
     */
    public function __construct($fileInput)
    {
        $this->name           = $_FILES[$fileInput]['name'];
        $this->size           = $_FILES[$fileInput]['size'];
        $this->tmp_name       = $_FILES[$fileInput]['tmp_name'];
        $this->type           = $_FILES[$fileInput]['type'];
        $this->error          = $_FILES[$fileInput]['error'];
        $this->fileExt        = strtolower(strrchr($this->name, '.'));
        $this->timeStamp      = time();
            
        $randChar = "abcdefghijklmnopqrstuvwxyz";
        $rndStr   = '';
        for($i = 0; $i <= 4; $i++)
        {
            $rndStr .= $randChar{rand(0,27)};
        }
        
        $this->newName        = $this->timeStamp.'-'.$rndStr.$this->fileExt;
        $this->maxSize        = 2097152; //2M
        $this->upDir          = $_SERVER['DOCUMENT_ROOT'].'/upload/'.date('Y-m', $this->timeStamp);
        $this->allowOverride  = false;
        
    }
    
    /**
     * 设定上传后的文件名
     *
     * @param string $newName
     * @return boolean
     */
    public function setNewName($newName='')
    {
        if($newName != '')
        {
            if (preg_match("/^[a-z0-9_-]*\.(.){1,5}$/i", $newName))
            {
                $this->newName = $newName;
                return true;
            }
            else
            {
                $this->error = 5;
            }
        }
        else 
        {
            return false;
        }
    }
    
    /**
     * 设定允许的扩展名
     *
     * @param array $validExt
     * @return boolean
     */
    public function setValidExt($validExt)
    {
        if(is_array($validExt))
        {
            $this->validExt = $validExt;
            return true;
        }
        else 
        {
            return false;
        }
    }
    
    /**
     * 设定允许的最大文件大小值
     *
     * @param int $maxSize
     * @return boolean
     */
    public function setMaxSize($maxSize)
    {
        if(isset($maxSize) && is_int($maxSize))
        {
            $this->maxSize = $maxSize;
            return true;
        }
        else 
        {
            $this->error = 6;
            return false;
        }
    }
    
    /**
     * 设定要上传到的文件路径，一般必须在类实例化后手工指定。
     * 注意：此方法无论目录是否存在均返回True。目录的合法性在调用Upload方法时判断
     *
     * @param string $updir
     * @return boolean
     */
    public function setUpDir($updir)
    {
        $this->upDir = $updir;
        return true;
    }
    
    /**
     * 处理上传，成功返回True，失败False。
     * 若上传失败，可以调用getErrorMsg()获取错误原因。
     *
     * @return boolean
     */
    public function upload()
    {
        if(file_exists($this->upDir.'/'.$this->newName) && !$this->allowOverride)
        {
            $this->error = 11;
            return false;
        }
        if($this->getErrorMsg())
        {
            return false;
        }
        if(is_uploaded_file($this->tmp_name))
        {
            if(!in_array($this->fileExt, $this->validExt))
            {
                $this->error = 7;
                return false;
            }
            if($this->size > $this->maxSize)
            {
                $this->error = 2;
                return false;
            }
            if (!is_dir($this->upDir))
            {
                umask(0);
                if(!mkdir($this->upDir, 0777))
                {
                    $this->error = 8;
                    return false;    
                }
            }
            if(!move_uploaded_file($this->tmp_name, $this->upDir.'/'.$this->newName))
            {
                $this->error = 9;
                return false;
            }
        }
        else 
        {
            $this->error = 10;
            return false;
        }
        
        return true;
    }
    
    /**
     * 获取上传的文件名
     *
     * @return string
     */
    public function getFileName()
    {
        return $this->newName;
    }
    
    /**
     * 获取上传的文件大小
     *
     * @return long
     */
    public function getFileSize()
    {
        return $this->size;
    }
    
    /**
     * 获取上传文件的完整物理路径
     *
     * @return string
     */
    public function getFilePath()
    {
        return $this->upDir.'/'.$this->newName;
    }
    
    /**
     * 获取错误信息，如果上传成功（无错误），则返回false
     *
     * @return mixed
     */
    public function getErrorMsg()
    {
        return $this->getErrorTxt($this->error);
    }
    
    /**
     * 私有方法，按错误号获取相应的错误信息
     *
     * @param int $needle
     * @return string
     */
    private function getErrorTxt($needle)
    {
        $validExtStr = '';
        foreach ($this->validExt as $validExt)
        {
            $validExtStr .= ' '.$validExt.' ';
        }
        $errorTxt[0] = False; //0: no Error.
        $errorTxt[1] = 'Sorry，上传的文件大小超出了服务器设定的最大值。';
        $errorTxt[2] = 'Sorry，文件超出了规定的大小，请确保您上传的文件不超过'.($this->maxSize/1024).'KB';
        $errorTxt[3] = '很倒霉，网络不稳定，上传中断，文件未完全上传:(';
        $errorTxt[4] = '您没有选择要上传的文件啊？';
        $errorTxt[5] = '文件名只允许英文字母和数字以及_-';
        $errorTxt[6] = '只能用数字设置文件的最大大小';
        $errorTxt[7] = '晕，不好意思，我们只允许上传如下扩展名的文件：'.$validExtStr;
        $errorTxt[8] = '指定的目录无法创建，文件上传失败';
        $errorTxt[9] = '未知错误，文件未Move成功';
        $errorTxt[10] = '未知错误，Is_Not_Uploaded_File';
        $errorTxt[11] = '遇到了发生率极小的同名文件错误，虽然文件未能成功上传，依然恭喜您';    
        
        return $errorTxt[$needle];
    }
}
?>